package com.bungarus.model;

import com.bungarus.codec.protobuf.MessageProtobuf;
import org.springframework.util.StringUtils;

/**
 * Created by tang on 2018/11/11.
 */
public class MessageBuilder {
    private static final String PREFIX = "ctnt";
    private static final SnowflakeIdMaker idMaker = new SnowflakeIdMaker(1, 0);
    public static final String TAG = "tag";

    public static MessageProtobuf.Message buildErrorMessage(int errCode, String errMsg) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(errCode)
                .build();

        StringBuffer sb = new StringBuffer(MessageBuilder.PREFIX);
        sb.append(":");
        sb.append(String.class.getCanonicalName());
        sb.append(":");
        sb.append(errMsg);

        MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                .setContent(sb.toString())
                .build();

        return MessageProtobuf.Message.newBuilder().setHeader(header).setBody(body).build();
    }

    public static MessageProtobuf.Message buildSucceedMessage(String sessionID, String token, Class contentClazz, String content) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(MessageStatus.OK)
                .setSessionId(sessionID)
                .setToken(token)
                .build();
        MessageProtobuf.Message.Builder builder = MessageProtobuf.Message.newBuilder().setHeader(header);
        if(!StringUtils.isEmpty(content)){
            StringBuffer sb = new StringBuffer(MessageBuilder.PREFIX);
            sb.append(":");
            sb.append(contentClazz.getCanonicalName());
            sb.append(":");
            sb.append(content);

            MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                    .setContent(sb.toString())
                    .build();

            builder.setBody(body);
        }
        return builder.build();
    }

    public static MessageProtobuf.Message buildAuthSucceed(String sessionID, String token) {
        return buildSucceedMessage(sessionID, token, String.class, null);
    }

    public static MessageProtobuf.Message buildTimeoutMessage() {
        return buildErrorMessage(MessageStatus.ERR_TIMEOUT, MessageStatus.ERR_TIMEOUT_DESC);
    }

    public static MessageProtobuf.Message buildAuthErrorMessage() {
        return buildErrorMessage(MessageStatus.ERR_AUTH, MessageStatus.ERR_AUTH_DESC);
    }

    public static MessageProtobuf.Message buildUserNonexistMessage() {
        return buildErrorMessage(MessageStatus.ERR_USER_NONEXIST, MessageStatus.ERR_USER_NONEXIST_DESC);
    }

    public static MessageProtobuf.Message buildAuthExpirationMessage() {
        return buildErrorMessage(MessageStatus.ERR_AUTH_EXPIRATION, MessageStatus.ERR_AUTH_EXPIRATION_DESC);
    }

    public static MessageProtobuf.Message buildSessionMessage(Session session) {
        //session will be to send to transfer, so the value of 'to' property in the message header
        //is set as Session.TAG. The remedy will use the 'to' property to get the right channel.
        //all messages must have a 'extension' contains 'tag={channelTag}' to make REMEDY using correct channel to
        //retry.
        MessageProtobuf.Extension extension = MessageProtobuf.Extension.newBuilder()
                .setKey(TAG)
                .setValue(Session.TAG)
                .build();
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(MessageStatus.OK)
                .setSessionId(session.getId())
                .setToken(session.getToken())
                .setApp(session.getApp())
                .setDev(session.getDev())
                .setTenantID(Integer.valueOf(session.getTenantId()))
                .setId(String.valueOf(idMaker.nextId()))
                .setFrom(session.getUserId())
                .setType(MessageType.AUTH)
                .setTo(Session.TAG)
                .setSentTime(System.currentTimeMillis())
                .addExtensions(extension)
                .build();
        MessageProtobuf.Message.Builder builder = MessageProtobuf.Message.newBuilder().setHeader(header);
        MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                .setContent("")
                .build();

        builder.setBody(body);
        return builder.build();
    }

    public static MessageProtobuf.Message buildRemedyMessage(MessageProtobuf.Message originMsg) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(MessageStatus.REMEDY)
                .setSessionId(originMsg.getHeader().getSessionId())
                .setToken(originMsg.getHeader().getToken())
                .setApp(originMsg.getHeader().getApp())
                .setDev(originMsg.getHeader().getDev())
                .setTenantID(originMsg.getHeader().getTenantID())
                .setId(originMsg.getHeader().getId())
                .setFrom(originMsg.getHeader().getFrom())
                .setTo(originMsg.getHeader().getTo())
                .setType(originMsg.getHeader().getType())
                .setSentTime(System.currentTimeMillis())
                .addAllExtensions(originMsg.getHeader().getExtensionsList())
                .build();
        MessageProtobuf.Message.Builder builder = MessageProtobuf.Message.newBuilder().setHeader(header);
        MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                .setContent(originMsg.getBody().getContent())
                .build();

        builder.setBody(body);
        return builder.build();
    }

    public static MessageProtobuf.Message buildHeartbeatPingMessage() {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setId(String.valueOf(idMaker.nextId()))
                .setType(MessageType.HEARTBEAT_PING)
                .build();
        MessageProtobuf.Message heartbeatPing = MessageProtobuf.Message.newBuilder()
                .setHeader(header)
                .build();

        return heartbeatPing;
    }

    public static MessageProtobuf.Message buildHeartbeatPingMessage(String from) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setId(String.valueOf(idMaker.nextId()))
                .setFrom(from)
                .setType(MessageType.HEARTBEAT_PING)
                .build();
        MessageProtobuf.Message heartbeatPing = MessageProtobuf.Message.newBuilder()
                .setHeader(header)
                .build();

        return heartbeatPing;
    }

    public static MessageProtobuf.Message buildHeartbeatPongMessage(String id) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setId(id)
                .setType(MessageType.HEARTBEAT_PONG)
                .build();
        MessageProtobuf.Message heartbeatPing = MessageProtobuf.Message.newBuilder()
                .setHeader(header)
                .build();

        return heartbeatPing;
    }

    public static MessageProtobuf.Message buildAckMessage(String messageId) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setId(messageId)
                .setType(MessageType.ACK)
                .build();

        MessageProtobuf.Message message = MessageProtobuf.Message.newBuilder()
                .setHeader(header)
                .build();
        return message;
    }

    public static MessageProtobuf.Message buildOfflineMessage(MessageProtobuf.Message originMsg) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(MessageStatus.OK)
                .setSessionId(originMsg.getHeader().getSessionId())
                .setToken(originMsg.getHeader().getToken())
                .setApp(originMsg.getHeader().getApp())
                .setDev(originMsg.getHeader().getDev())
                .setTenantID(originMsg.getHeader().getTenantID())
                .setId(originMsg.getHeader().getId())
                .setFrom(originMsg.getHeader().getFrom())
                .setTo(originMsg.getHeader().getTo())
                .setType(MessageType.OFFLINE)
                .setSentTime(originMsg.getHeader().getSentTime())
                .addAllExtensions(originMsg.getHeader().getExtensionsList())
                .build();
        MessageProtobuf.Message.Builder builder = MessageProtobuf.Message.newBuilder().setHeader(header);
        MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                .setContent(originMsg.getBody().getContent())
                .build();

        builder.setBody(body);
        return builder.build();
    }

    public static MessageProtobuf.Message cloneMessageWithNewId(MessageProtobuf.Message originMsg) {
        MessageProtobuf.Header header = MessageProtobuf.Header.newBuilder()
                .setReturnCode(MessageStatus.OK)
                .setSessionId(originMsg.getHeader().getSessionId())
                .setToken(originMsg.getHeader().getToken())
                .setApp(originMsg.getHeader().getApp())
                .setDev(originMsg.getHeader().getDev())
                .setTenantID(originMsg.getHeader().getTenantID())
                .setId(String.valueOf(idMaker.nextId()))
                .setFrom(originMsg.getHeader().getFrom())
                .setTo(originMsg.getHeader().getTo())
                .setType(MessageType.CLONE)
                .setSentTime(originMsg.getHeader().getSentTime())
                .addAllExtensions(originMsg.getHeader().getExtensionsList())
                .build();
        MessageProtobuf.Message.Builder builder = MessageProtobuf.Message.newBuilder().setHeader(header);
        MessageProtobuf.Body body = MessageProtobuf.Body.newBuilder()
                .setContent(originMsg.getBody().getContent())
                .build();

        builder.setBody(body);
        return builder.build();
    }
}
